package com.br.aiops.storage.counter;

import com.alibaba.fastjson.JSONObject;
import com.br.aiops.counter.AlertLogCounter;
import com.br.aiops.counter.CounterLadderValue;
import com.br.aiops.listeners.ladder.LadderCycleStatus;
import com.br.aiops.listeners.ladder.LadderCycleStatusCache;
import com.br.aiops.schedule.AbstractSchedule;
import com.br.aiops.schedule.Schedules;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.List;
import java.util.Objects;

@Service
public class StorageCounterService {

    private static final Logger LOGGER = LoggerFactory.getLogger(StorageCounterService.class);

    @Autowired
    private CounterRepository counterRepository;

    @Autowired
    private CounterScheduleStatusRepository counterScheduleStatusRepository;

    @Autowired
    private CounterLadderValueRepository counterLadderValueRepository;

    @Autowired
    private CounterLadderStatusRepository counterLadderStatusRepository;

    @Autowired
    private Schedules schedules;

    /**
     * 持久化counter
     * @param alertLogCounters 保存的counters
     */
    public void storageCounter(Collection<AlertLogCounter> alertLogCounters) {
        alertLogCounters.forEach(alertLogCounter -> {
            //保存counter的值
            saveCounter(alertLogCounter);
            //保存调度器区间的值或阶梯值
            saveCounterStatus(alertLogCounter);
        });
    }

    /**
     * 标记为恢复状态
     * @param counterKey
     */
    public void resume(String counterKey) {
        counterRepository.resume(counterKey);
    }

    /**
     * 清理已恢复的数据
     */
    public void deleteResume() {
        List<CounterDTO> counters = counterRepository.findByResume();
        if (Objects.nonNull(counters)) {
            counters.forEach(counterDTO -> {
                AlertLogCounter counter = JSONObject.parseObject(counterDTO.getValue(), AlertLogCounter.class);
                if (counter.shouldLadderAlert()) {
                    //清理ladder status数据
                    counterLadderStatusRepository.deleteByKey(counterDTO.getKey());
                    //清理ladder value数据
                    counterLadderValueRepository.deleteByKey(counter.counterKey());
                } else {
                    //清理schedule status数据
                    counterScheduleStatusRepository.deleteByKey(counterDTO.getKey());
                }
                //清除counter
                counterRepository.delete(counterDTO);
            });
        }
    }

    private void saveCounterStatus(AlertLogCounter alertLogCounter) {
        if (alertLogCounter.shouldLadderAlert()) {
            saveLadderValue(alertLogCounter);
            saveLadderStatus(alertLogCounter);
        } else {
            saveScheduleStatus(alertLogCounter);
        }
    }

    /**
     * 保存阶梯value
     * @param alertLogCounter
     */
    private void saveLadderValue(AlertLogCounter alertLogCounter) {
        String counterKey = alertLogCounter.counterKey();
        CounterLadderValueDTO ladderValueDTO = CounterLadderValueDTO.builder()
                .counterKey(counterKey)
                .ladderValue(JSONObject.toJSONString(CounterLadderValue.getLadderValue(counterKey)))
                .build();
        CounterLadderValueDTO dbLadderValueDTO = counterLadderValueRepository.findLadderValue(counterKey);
        if (Objects.nonNull(dbLadderValueDTO)) {
            ladderValueDTO.setId(dbLadderValueDTO.getId());
        }
        counterLadderValueRepository.save(ladderValueDTO);
    }

    /**
     * 保存阶梯的统计状态
     * @param alertLogCounter
     */
    private void saveLadderStatus(AlertLogCounter alertLogCounter) {
        String counterKey = alertLogCounter.counterKey();
        LadderCycleStatus ladderCycleStatus = LadderCycleStatusCache.getLadderCycleStatus().getOrDefault(counterKey, new LadderCycleStatus(alertLogCounter));

        CounterLadderStatusDTO ladderStatusDTO = CounterLadderStatusDTO.builder()
                .counterKey(counterKey)
                .ladderCycleStatus(JSONObject.toJSONString(ladderCycleStatus))
                .build();

        CounterLadderStatusDTO dbLadderStatusDTO = counterLadderStatusRepository.findByCounterKey(counterKey);
        if (Objects.nonNull(dbLadderStatusDTO)) {
            ladderStatusDTO.setId(dbLadderStatusDTO.getId());
        }
        counterLadderStatusRepository.save(ladderStatusDTO);
    }

    /**
     * 保存调度器的统计状态
     * @param alertLogCounter
     */
    private void saveScheduleStatus(AlertLogCounter alertLogCounter) {
        String counterKey = alertLogCounter.counterKey();
        AbstractSchedule schedule = getSchedule(alertLogCounter.getRule().getDuration());
        CounterScheduleStatusDTO scheduleStatusDTO = CounterScheduleStatusDTO.builder()
                .counterKey(alertLogCounter.counterKey())
                .currentStatus(JSONObject.toJSONString(schedule.getCurrentCountStatus().getOrDefault(counterKey, new AbstractSchedule.Status())))
                .prevStatus(JSONObject.toJSONString(schedule.getPrevCountStatus().getOrDefault(counterKey, new AbstractSchedule.Status())))
                .scheduleCycle(JSONObject.toJSONString(schedule.getCycle()))
                .build();
        LOGGER.info("schedule current status: {}, prev status: {}.", scheduleStatusDTO.getCurrentStatus(), scheduleStatusDTO.getPrevStatus());

        CounterScheduleStatusDTO dbScheduleStatusDTO = counterScheduleStatusRepository.findByCounterKey(counterKey);
        if (Objects.nonNull(dbScheduleStatusDTO)) {
            scheduleStatusDTO.setId(dbScheduleStatusDTO.getId());
        }
        counterScheduleStatusRepository.save(scheduleStatusDTO);
    }

    /**
     * 保存全局counter统计状态
     * @param alertLogCounter
     */
    private void saveCounter(AlertLogCounter alertLogCounter) {
        CounterDTO counterDTO = CounterDTO.builder()
                .partition(alertLogCounter.getAlertLog().getPartition())
                .key(alertLogCounter.counterKey())
                .value(JSONObject.toJSONString(alertLogCounter))
                .build();
        //如果存在则更新
        CounterDTO dbCounterDTO = counterRepository.findByKey(alertLogCounter.counterKey());
        if (Objects.nonNull(dbCounterDTO)) {
            counterDTO.setId(dbCounterDTO.getId());
        }
        counterRepository.save(counterDTO);
        //防止已经恢复的告警状态为未恢复
        counterRepository.setNotResume(alertLogCounter.counterKey());
    }

    private AbstractSchedule getSchedule(int duration) {
        return schedules.getSchedule(duration);
    }
}
